/*
 * Copyright (c) 2019- 2019 threefish(https://gitee.com/threefish https://github.com/threefish) All Rights Reserved.
 * 本项目完全开源，商用完全免费。但请勿侵犯作者合法权益，如申请软著等。
 * 最后修改时间：2019/10/07 18:27:07
 * 源 码 地 址：https://gitee.com/threefish/NutzFw
 */

package com.nutzfw.core.plugin.view;

import com.nutzfw.core.common.util.StringUtil;
import org.beetl.core.ErrorHandler;
import org.beetl.core.Resource;
import org.beetl.core.exception.BeetlException;
import org.beetl.core.exception.ErrorInfo;
import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.Mvcs;

import java.io.IOException;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author 黄川 huchuc@vip.qq.com
 * @date: 2019/2/18
 */
public class BeetlWebErrorHandler implements ErrorHandler {

    private static final Log log = Logs.get();

    private static final String HTML = "<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><meta name=\"robots\" content=\"noindex,nofollow\"><title>500 - 系统错误</title><style>body{font-size: 14px;font-family: 'helvetica neue',tahoma,arial,'hiragino sans gb','microsoft yahei','Simsun',sans-serif; background-color:#fff; color:#808080;} .wrap{margin:0 auto;width:800px;margin-top: 10%;} td{text-align:left; padding:2px 10px;}td.header{font-size:22px; padding-bottom:10px; color:#000;} td.check-info{padding-top:20px;}  a{color:#328ce5; text-decoration:none;} a:hover{text-decoration:underline;} pre{overflow: auto;width: 800px;max-height: 200px;margin: auto;border: 1px #cdcdcd solid;background: #f5f0f0;padding: 10px;}</style></head><body><div class=\"wrap\"><table><tr><td rowspan=\"5\" style=\"\"><img src=\"\"></td>" +
            "<td class=\"header\">很抱歉！当前页面出错了！</td></tr>" +
            "[INFO]" +
            "<tr><td>如果刷新页面没能解决问题，你可以联系网站管理员进行反馈。</td></tr>" +
            "<tr><td class=\"check-info\">或者，你也可以<a href=\"/\">跳转到首页</a></td></tr></table></div></body></html>";

    private static final String INFO = "<tr><td>错误信息：<pre>[TITLE]</pre></td></tr><tr><td>详情：<pre>[MSG]</pre></td></tr>";

    @Override
    public void processExcption(BeetlException ex, Writer writer) {

        ErrorInfo error = new ErrorInfo(ex);
        StringBuilder msg = new StringBuilder();
        StringBuilder title = new StringBuilder();
        if (error.getErrorCode().equals(BeetlException.CLIENT_IO_ERROR_ERROR)) {
            //不输出详细提示信息
            if (!ex.gt.getConf().isIgnoreClientIOError()) {
                title.append("客户端IO异常:" + getResourceName(ex.resource.getId()) + ":" + error.getMsg()).append("\n");
                if (ex.getCause() != null) {
                    this.render(writer, title.toString(), ex.getMessage());
                }
                return;
            }
        }
        int line = error.getErrorTokenLine();
        StringBuilder sb = new StringBuilder(">>").append(this.getDateTime()).append(":").append(error.getType())
                .append(":").append(error.getErrorTokenText()).append(" 位于").append(line != 0 ? line + "行" : "").append(" 资源:")
                .append(getResourceName(ex.resource.getId()));
        if (error.getErrorCode().equals(BeetlException.TEMPLATE_LOAD_ERROR)) {
            if (error.getMsg() != null) {
                sb.append(error.getMsg()).append("\n");
            }
            title.append(ex.gt.getResourceLoader().getInfo()).append("\n");
            title.append(sb.toString()).append("\n");
        } else if (ex.getMessage() != null) {
            title.append(ex.getMessage()).append("\n");
        }
        try {
            Resource res = ex.resource;
            //显示前后三行的内容
            int[] range = this.getRange(line);
            String content = res.getContent(range[0], range[1]);
            if (content != null && ex.cr != null) {
                String[] strs = content.split(ex.cr);
                int lineNumber = range[0];
                for (int i = 0; i < strs.length; i++) {
                    msg.append("" + lineNumber);
                    msg.append("|");
                    msg.append(strs[i]).append("\n");
                    lineNumber++;
                }
            }
        } catch (Exception e) {
            //ingore
        }
        if (error.getResourceCallStack() != null && error.hasCallStack()) {
            title.append("  ========================").append("\n");
            title.append("  调用栈:").append("\n");
            for (int i = 0; i < error.getResourceCallStack().size(); i++) {
                title.append("  " + error.getResourceCallStack().get(i) + " 行：" + error.getTokenCallStack().get(i).line).append("\n");
            }
        }
        if(Strings.isBlank(msg)){
            msg.append(StringUtil.throwableToString(ex));
        }
        this.render(writer, title.toString(), msg.toString());
        log.error(ex);
        try {
            writer.flush();
        } catch (IOException e) {

        }
    }

    public void render(Writer writer, String title, String msg) {
        try {
            //在进入这里之前 writer 已经写入一些信息了，需要重置下输出流
            if (!Mvcs.getResp().isCommitted()) {
                Mvcs.getResp().reset();
            }
            if (BeetlViewMaker.isDev) {
                writer.write(HTML.replace("[INFO]", INFO.replace("[TITLE]", Strings.escapeHtml(title)).replace("[MSG]", Strings.escapeHtml(msg))));
            } else {
                writer.write(HTML.replace("[INFO]", ""));
            }
            log.debugf("模版错误：%s \n 错误详情：\n%s", title, msg);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    protected String getResourceName(String resourceId) {
        return resourceId;
    }


    protected int[] getRange(int line) {
        int startLine = 0;
        int endLine = 0;
        if (line > 3) {
            startLine = line - 3;
        } else {
            startLine = 1;
        }
        endLine = startLine + 6;
        return new int[]{startLine, endLine};
    }

    protected String getDateTime() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");
        return sdf.format(date);
    }


}
